Skip to content

fix: hide Python activity bar icon in non-Python workspaces - #1663

Open
Mohit Yadav (mohityadav8) wants to merge 6 commits into
microsoft:mainfrom
mohityadav8:fix/conditional-activity-bar-icon-v2
Open

fix: hide Python activity bar icon in non-Python workspaces#1663
Mohit Yadav (mohityadav8) wants to merge 6 commits into
microsoft:mainfrom
mohityadav8:fix/conditional-activity-bar-icon-v2

Conversation

@mohityadav8

Copy link
Copy Markdown
Contributor

Fixes microsoft/vscode-python#26015

Added context key python-envs.workspaceHasPython via findFiles + FileSystemWatcher. ANDed into when clauses of the activitybar container and both views.

Fixes microsoft/vscode-python#26015

Added context key python-envs.workspaceHasPython via findFiles + FileSystemWatcher.
ANDed into when clauses of the activitybar container and both views.

Signed-off-by: Mohit Yadav <ymohit799057@gmail.com>
@mohityadav8
Mohit Yadav (mohityadav8) marked this pull request as ready for review July 25, 2026 15:04
Comment thread src/features/views/workspacePythonContext.ts

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contributions!
LGTML :)

@edvilme Eduardo Villalpando Mello (edvilme) added the bug Issue identified by VS Code Team member as probable bug label Jul 28, 2026
@mohityadav8

Copy link
Copy Markdown
Contributor Author

hi @edvilme Both CI failures are unrelated to this PR's changes:

1. Check for changed files (package-lock.json)
The package.json edits in this PR only modify the contributes section (VS Code metadata-- viewsContainers and views when clauses).No npm dependencies were added or changed, so package-lock.json does not need updating . Could a maintainer add the skip package*.json label to pass this check?

2. Integration test failure (pythonProjects.integration.test.js:150)

The failure is:
AssertionError: Retrieved environment should match set environment

'Python 3.14.6.final.0-j5ae0pzs6ek'
'Python 3.14.6.final.0-m8ni2jdqggb'
This is a pre-existing flaky test comparing non-deterministic environment hash suffixes. It is not triggered by any code in this PR -- the new file (workspacePythonContext.ts) and the changes to extension.ts and package.json have no interaction with environment resolution or the project manager.

Comment thread package.json
"icon": "files/logo.svg",
"contextualTitle": "Python Projects",
"when": "config.python.useEnvironmentsExtension != false"
"when": "config.python.useEnvironmentsExtension != false && python-envs.workspaceHasPython"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR hides the activity-bar icon unless this context key is true:

python-envs.workspaceHasPython

That key is not defined initially. It only gets set after the extension’s  activate()  function runs:

registerWorkspacePythonContext(context.subscriptions);

However,  package.json currently activates the extension only when VS Code opens a Python-language document:

"activationEvents": [ "onLanguage:python" ]

This creates a circular dependency:

  1. The extension must activate to detect Python files and set the context key.
  2. The activity-bar icon is hidden until that key is set.
  3. A hidden view cannot be opened to activate the extension.
  4. If no  .py  file is opened,  onLanguage:python never activates the extension.

Example

A user opens a repository containing:

my-project/
├── pyproject.toml
├── requirements.txt
└── README.md

The repository is clearly a Python project, but the user has not opened a  .py  file yet.

Expected: The Python activity-bar icon appears because pyproject.toml  identifies the workspace as Python.

Actual: The extension does not activate, so it never searches for  pyproject.toml . The context key remains unset, and the icon stays hidden.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Fix is to add workspaceContains activation events to package.json so the extension activates even before a .py file is opened:

"activationEvents": [
"onLanguage:python",
"workspaceContains:**/*.py",
"workspaceContains:pyproject.toml",
"workspaceContains:requirements.txt",
"workspaceContains:Pipfile",
"workspaceContains:setup.py",
"workspaceContains:mspythonconfig.json",
"workspaceContains:.venv",
"workspaceContains:.conda"
]

This breaks the circular dependency - extension activates when any marker file is present in the workspace, sets the context key, and the icon appears without needing a .py file open first.

const EXCLUDE = '**/{node_modules,.git,site-packages}/**';

async function refresh(): Promise<void> {
const hits = await findFiles(MARKER_GLOB, EXCLUDE, 1);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this only searching inside open workspaces folders. What if user opens a standalone Python file without opening the folder?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

findFiles only searches workspace folders, so standalone file case is missed. Will add a fallback check on open text documents:

async function refresh(): Promise<void> {
    const hits = await findFiles(MARKER_GLOB, EXCLUDE, 1);
    if (hits.length > 0) {
        await executeCommand('setContext', PYTHON_WORKSPACE_KEY, true);
        return;
    }
    const hasPythonDoc = workspace.textDocuments.some(
        (doc) => doc.languageId === 'python',
    );
    await executeCommand('setContext', PYTHON_WORKSPACE_KEY, hasPythonDoc);
}

And subscribe to onDidOpenTextDocument in registerWorkspacePythonContext.


export function registerWorkspacePythonContext(disposables: Disposable[]): void {
const watcher = createFileSystemWatcher(MARKER_GLOB, false, true, false);
disposables.push(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is EXCLUDE only passed to findFiles() but not the createFileSystemWatchter? Does that mean the watcher still listens for every .py  file created or deleted under site-packages? I am a bit worried about the perf here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct-- createFileSystemWatcher has no exclude parameter in the VS Code API, so it fires for site-packages too. Fix is to filter in the event handlers:

const EXCLUDE_RE = /[\\/](node_modules|\.git|site-packages)[\\/]/;

watcher.onDidCreate((uri) => { if (!EXCLUDE_RE.test(uri.fsPath)) void refresh(); }),
watcher.onDidDelete((uri) => { if (!EXCLUDE_RE.test(uri.fsPath)) void refresh(); }),

This avoids unnecessary refresh() calls from excluded directories.

@edvilme

Copy link
Copy Markdown
Contributor

Hello Mohit Yadav (@mohityadav8) thanks for following on with the reviews. I think there is still one unresolved issue and a merge conflict before we can take another look :)

@mohityadav8

Copy link
Copy Markdown
Contributor Author

Hello @mohityadav8 thanks for following on with the reviews. I think there is still one unresolved issue and a merge conflict before we can take another look :)

Solve conflict can u please share what's the issue I forgot to see in workflow

…oft#1651)

> Part of microsoft#1602 (PEP 723 inline script env support). Design doc: microsoft#1601.

> **Split for review (3 PRs).** Reviewers flagged the original PR 5 as
too large, so it is split into three stacked PRs grouped by dependency
layer:
> - **5a — generic env-creation utilities — this PR (microsoft#1651).** Based on
`main`; independent; merges first.
> - **5b — inline-script cache + interpreter utilities — microsoft#1655.**
Stacked on 5a.
> - **5c — `create()` happy path (manager + wiring) — microsoft#1656.** Stacked
on 5b.
>
> Applied together the three PRs are byte-for-byte identical to the
original single change. **Merge order: 5a → 5b → 5c.**

### Roadmap context

This is the first slice of **PR 5 of 16** in the PEP 723 inline-script
roadmap. The full plan lives in microsoft#1602.

| Phase | PR | Status |
|---|---|---|
| **Phase 1: Foundation** | PR 1: cache key hash utility | merged
(microsoft#1634) |
| | PR 2: cache layout + `meta.json` sidecar | merged (microsoft#1635) |
| | PR 3: `requires-python` to interpreter selection | merged (microsoft#1636) |
| **Phase 2: Manager** | PR 4: `InlineScriptEnvManager` skeleton |
merged (microsoft#1610) |
| | **PR 5a: generic env-creation utilities** | **this PR (microsoft#1651)** |
| | **PR 5b: inline-script cache + interpreter utilities** | **microsoft#1655** |
| | **PR 5c: `create()` happy path (manager + wiring)** | **microsoft#1656** |
| | PR 6: `create()` uv-install fallback | not started (needs 3, 5) |
| | PR 7: persistence with `get`, `set`, and Memento | not started
(needs 4) |
| | PR 8: activation-time discovery | not started (needs 2, 4, 7) |
| **Phase 3: Routing** | PR 9: route PEP 723 scripts to the inline
manager | not started (needs 4, 7) |
| | PR 10: per-script project registration | not started (needs 9) |
| **Phase 4+: UX / lifecycle** | PRs 11-16 | not started |

### Why this PR

PR 5c implements `InlineScriptEnvManager.create()`. Before touching the
manager, this PR lands the **generic, reusable primitives** it relies on
— a cross-process file lock, a venv Python-path helper, a
cancellation-hardened process runner, and two small `createWithProgress`
options. None of this code is inline-script-specific, so it is reviewed
on its own.

### What this PR adds

**Cross-process file lock** (`src/common/lockfile.apis.ts`, new):
`acquireFileLock` uses an atomic `mkdir` of a `<path>.lock` directory
plus a per-owner marker file, returning `AcquiredFileLock { release,
retain }`. `retain()` writes a `retained` marker so a later acquirer
**fails fast with `ELOCKRETAINED`** instead of waiting out the 5-minute
timeout — used when a build is cancelled mid-flight. Distinct error
codes (`ELOCKED`, `ELOCKRETAINED`, `ELOCKORPHANED`, `ECOMPROMISED`,
`ERETAINFAILED`) separate contention from corruption.

**Shared `getVenvPythonPath`**
(`src/common/utils/virtualEnvironment.ts`, new): returns
`Scripts\python.exe` on Windows, else `bin/python`. Replaces an inline
copy in `venvUtils` and is reused by 5b/5c.

**Hardened process helper** (`src/managers/builtin/helpers.ts`): `runUV`
and `runPython` now share one `runProcess` implementation whose
cancellation guards `kill()` in `try/catch` and still emits a clean
`CancellationError` if the process errors after a cancel. Per-caller
options preserve existing behavior (`collectStderr`, `logPrefix`).

**`venvUtils.ts`:** `createWithProgress` gains
`CreateWithProgressOptions { trackUvEnvironment }`, and
`CreateEnvironmentResult` gains `pkgInstallationCancelled` so a caller
can tell cancellation apart from a real install failure. Existing
callers are unaffected (both are optional / additive).

### Tests

- **`lockfile.apis.unit.test.ts`** — 9 tests: contention,
retain/fail-fast, orphaned and compromised locks, and timeout.
- **`virtualEnvironment.unit.test.ts`** — 2 tests for
`getVenvPythonPath` on Windows and POSIX.
- **`helpers.cancellation.unit.test.ts`** — 4 tests for `runProcess`
cancellation safety.
- **`venvUtils.createWithProgress.unit.test.ts`** — 3 tests for
`trackUvEnvironment` and `pkgInstallationCancelled`.

On this branch alone `npm run compile-tests` is clean and `npm run
unittest` reports **1447 passing, 0 failing, 4 pending**.

### User impact

**None.** These are internal primitives with no new user-visible
behavior. The refactors to `helpers.ts` and `venvUtils.ts` are
behavior-preserving for existing callers.

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 39dcc6a3-0fbd-4f36-9d0f-68677de49c27
## Summary

- remove the extension-level Marketplace preview designation
- remove stale README language about the completed rollout
- retain labels for individual features that are still experimental

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…#1670)

The `version-match` CI job blocked release PRs (e.g. microsoft#1668) whenever the
extension and API package versions diverged. These versions should be
independent — the API package is separately published and versioned.

## Changes

- **`api/package.json`** — Reset version `1.37.0` → `1.0.0`
- **`api/package-lock.json`** — Reset both root-level and `packages[""]`
version fields to match
- **`.github/workflows/pr-file-check.yml`** — Remove the `version-match`
job entirely; the check requiring `api/package.json` to be bumped on
public API changes (`src/api.ts`) is preserved

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
@mohityadav8
Mohit Yadav (mohityadav8) force-pushed the fix/conditional-activity-bar-icon-v2 branch from 5a4705f to f922e06 Compare August 6, 2026 05:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Signed-off-by: Mohit Yadav <ymohit799057@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Issue identified by VS Code Team member as probable bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Show Python in activity bar conditionally

6 participants